#include "graphicdatamodel.h"

#include "../../editors/ieditoritem.h"

using namespace core;

GraphicDataModel::GraphicDataModel() :
    m_allModelConnections(),
    m_categorizedItems(),
    m_items(),
    m_nodes(),
    m_graph(false)
{

}

GraphicDataModel::~GraphicDataModel()
{

}

void GraphicDataModel::addModelItem(IGraphicEditorItem* item)
{
    if (!m_items.contains(item->id()))
    {
        m_items[item->id()] = item;

        if (!m_categorizedItems.contains(item->type()))
        {
            QList<IGraphicEditorItem* > itemList;
            itemList << item;

            m_categorizedItems[item->type()][item->name()] = itemList;
        }
        else
        {
            if (!m_categorizedItems[item->type()].contains(item->name()))
            {
                m_categorizedItems[item->type()][item->name()] =
                    QList<IGraphicEditorItem* >();
            }

            m_categorizedItems[item->type()][item->name()].append(item);
        }
    }
}

void GraphicDataModel::removeModelItem(IGraphicEditorItem* item)
{
    if (m_items.contains(item->id()))
    {
        m_items.remove(item->id());

        if (m_categorizedItems[item->type()][item->name()].size() > 1)
        {
            m_categorizedItems[item->type()][item->name()].removeAll(item);
        }
        else if (m_categorizedItems[item->type()][item->name()].size() == 1)
        {
            m_categorizedItems[item->type()].remove(item->name());
        }

        if (m_categorizedItems[item->type()].size() == 0)
        {
            m_categorizedItems.remove(item->type());
        }
    }
}

void GraphicDataModel::addModelConnection(const ConnectionData& data)
{
    if (!m_allModelConnections.contains(data))
    {
        Node* fromNode;
        Node* toNode;

        IGraphicEditorItem* from = dynamic_cast<IGraphicEditorItem* >(
            data.From);
        IGraphicEditorItem* to = dynamic_cast<IGraphicEditorItem* >(data.To);

        Q_ASSERT(from != 0 && to != 0); // bad type of items

        if (!m_nodes.contains(from))
        {
            fromNode = Node::create(from);

            m_nodes[from] = fromNode;
        }
        else
        {
            fromNode = m_nodes[from];
        }

        if (!m_nodes.contains(to))
        {
            toNode = Node::create(to);

            m_nodes[to] = toNode;
        }
        else
        {
            toNode = m_nodes[to];
        }

        m_allModelConnections.append(data);

        m_graph.connect(fromNode, toNode, &m_allModelConnections.last());
    }
}

void GraphicDataModel::removeModelConnection(const ConnectionData& data)
{
    if (m_allModelConnections.contains(data))
    {
        IGraphicEditorItem* from = dynamic_cast<IGraphicEditorItem* >(
            data.From);
        IGraphicEditorItem* to = dynamic_cast<IGraphicEditorItem* >(data.To);

        Q_ASSERT(from != 0 && to != 0); // bad type of items

        if (m_nodes.contains(from) && m_nodes.contains(to) &&
            m_graph.getEdge(m_nodes[from], m_nodes[to]))
        {
            m_graph.disconnect(m_nodes[from], m_nodes[to]);
        }

        m_allModelConnections.removeAll(data);
    }
}

bool GraphicDataModel::hasItem(QUuid id) const
{
    bool ret = m_items.contains(id);

    return ret;
}

Node* GraphicDataModel::getNode(IGraphicEditorItem* item) const
{
    if (m_nodes.contains(item))
    {
        return m_nodes[item];
    }
    else
    {
        return 0;
    }
}

const DirectedGraph* GraphicDataModel::graphRepresentation() const
{
    return &m_graph;
}

void GraphicDataModel::clearModel()
{
    m_categorizedItems.clear();
    m_items.clear();
    m_nodes.clear();
    m_graph.clear();
    m_allModelConnections.clear();
}
